import type {
  AxiosRequestConfig,
  AxiosInstance,
  AxiosResponse,
  AxiosError,
} from "axios";

import type { RequestOptions, UploadFileParams, Result } from "/#/axios";
import { ContentTypeEnum, CreateAxiosOptions } from "./AxiosOptions";

import axios from "axios";
export default class HttpClient {
  private axiosInstance: AxiosInstance;
  private readonly options: CreateAxiosOptions;

  constructor(options: CreateAxiosOptions) {
    this.options = options;
    this.axiosInstance = axios.create(options);
    this.setupInterceptors();
  }
  setupInterceptors() {
    this.axiosInstance.interceptors.request.use(
      (config: AxiosRequestConfig) => {
        return config;
      },
      undefined
    );

    this.axiosInstance.interceptors.request.use(
      undefined,
      (error: Error) => {}
    );

    this.axiosInstance.interceptors.response.use((res: AxiosResponse<any>) => {
      return res;
    }, undefined);

    this.axiosInstance.interceptors.response.use(undefined, (error) => {});
  }
  setHeader(headers: any): void {
    if (!this.axiosInstance) {
      return;
    }
    Object.assign(this.axiosInstance.defaults.headers, headers);
  }

  download(url: string, fuc:(any), config?: AxiosRequestConfig | undefined) {
    this.axiosInstance.get(url,config).then(
      function(x) {
       fuc(x.data)
      }
    )
  }

  /**
   * @description:  File Upload
   */
  uploadFile<T = any>(config: AxiosRequestConfig, params: UploadFileParams) {
    const formData = new window.FormData();
    const customFilename = params.name || "file";

    if(params.file instanceof FileList) {
      for(let i = 0; i < params.file.length; i++) {
        let file = params.file[i]
        formData.append(customFilename, file)
      }
    } 
    else if (params.filename) {
      formData.append(customFilename, params.file, params.filename);
    } else {
      formData.append(customFilename, params.file);
    }

    if (params.data) {
      Object.keys(params.data).forEach((key) => {
        const value = params.data![key];
        if (Array.isArray(value)) {
          value.forEach((item) => {
            formData.append(`${key}[]`, item);
          });
          return;
        }

        formData.append(key, params.data![key]);
      });
    }
    config.data = formData;
    config.headers = {
      'Content-type': ContentTypeEnum.FORM_DATA
    }    
    return this.request<T>({...config, method: 'POST'});
  }
  get<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: 'GET' }, options);
  }

  post<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: 'POST' }, options);
  }

  put<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: 'PUT' }, options);
  }

  delete<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    return this.request({ ...config, method: 'DELETE' }, options);
  }

  request<T = any>(config: AxiosRequestConfig, options?: RequestOptions): Promise<T> {
    // let conf: CreateAxiosOptions = cloneDeep(config);
    // const transform = this.getTransform();

    // const { requestOptions } = this.options;

    // const opt: RequestOptions = Object.assign({}, requestOptions, options);

    // const { beforeRequestHook, requestCatchHook, transformResponseHook } = transform || {};
    // if (beforeRequestHook && isFunction(beforeRequestHook)) {
    //   conf = beforeRequestHook(conf, opt);
    // }
    // conf.requestOptions = opt;

    // conf = this.supportFormData(conf);

    return new Promise((resolve, reject) => {
      this.axiosInstance
        .request<any, AxiosResponse<Result>>(config)
        .then((res: AxiosResponse<Result>) => {          
            try {      
              let {data} = res
              let result = data as Result     
              resolve(result.result);
            } catch (err) {
              reject(err || new Error('request error!'));
            }
            return;
        })
        .catch((e: Error | AxiosError) => {
          //if (requestCatchHook && isFunction(requestCatchHook)) {
            reject(e);
            return;
          //}
          if (axios.isAxiosError(e)) {
            // rewrite error message from axios in here
          }
          reject(e);
        });
    });
  }
}
